/*
 *    Copyright (C) 2005, 2006, 2007, 2008  Glauber Magalh�es Pires
 *
 *    This file is part of OpenP2M.
 *
 *    OpenP2M is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    OpenP2M is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with OpenP2M.  If not, see <http://www.gnu.org/licenses/>.
 */
package core.crypto;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.SecureRandom;

/**
 * @author Glauber Magalh�es Pires
 * 
 */
public class RSA {
	public final String encriptar(String original) {
		try {
			BigInteger numero = new BigInteger(original.getBytes("ISO-8859-1"));
			BigInteger encriptado = this.encrypt(numero);
			String strEncriptado = "_" + encriptado.toString(36);
			return strEncriptado;
		} catch (UnsupportedEncodingException ex) {
			return ex.getMessage();
		}
	}

	public final String desencriptar(String senhaEncriptada)
			throws NumberFormatException {
		String desencriptado;
		if (senhaEncriptada.startsWith("_"))
			desencriptado = new String(this.decrypt(
					new BigInteger(senhaEncriptada.substring(1), 36))
					.toByteArray());
		else if (senhaEncriptada.startsWith("+"))
			desencriptado = new String(this.decrypt(
					new BigInteger(senhaEncriptada.substring(1), 36))
					.toByteArray());
		else
			desencriptado = new String(this.decrypt(
					new BigInteger(senhaEncriptada)).toByteArray());
		return desencriptado;
	}

	private BigInteger publicKey, privateKey, e;

	public RSA(int bitlen) {
		SecureRandom r = new SecureRandom();
		BigInteger p = new BigInteger(bitlen / 2, 100, r);
		BigInteger q = new BigInteger(bitlen / 2, 100, r);
		publicKey = p.multiply(q);
		BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q
				.subtract(BigInteger.ONE));
		e = new BigInteger("3");
		while (m.gcd(e).intValue() > 1)
			e = e.add(new BigInteger("2"));
		privateKey = e.modInverse(m);
	}

	public RSA(BigInteger e, BigInteger privateKey, BigInteger publicKey) {
		this.e = e;
		this.privateKey = privateKey;
		this.publicKey = publicKey;
	}

	public RSA() {
		this.e = new BigInteger("5");
		this.privateKey = null;
		this.publicKey = new BigInteger(
				"8496133897567932221559267089164065267221377078566337104866771208480189113695076911576868324903413008512741498700587851315525414979963642608998181269527941");
	}

	private BigInteger encrypt(BigInteger message) {
		return message.modPow(e, publicKey);
	}

	private BigInteger decrypt(BigInteger message) {
		if (privateKey == null)
			throw new RuntimeException("Esta compilacao n�o dispoe da CHAVE de decodifica��o para as senhas do openp2m.");
		return message.modPow(privateKey, publicKey);
	}
}
